package library.console;

import library.ErrorCode;
import library.ErrorMessage;
import library.controller.BookController;
import library.controller.BorrowController;
import library.controller.ReaderController;
import library.entity.Book;
import library.entity.BookingRecord;
import library.entity.Reader;

import java.sql.SQLException;
import java.util.*;

public class BorrowMenu {
	Scanner scanner;
	Reader currentReader;
	ReaderController readerController;
	BookController bookController;
	BorrowController bookingController;

	public BorrowMenu(Scanner sc) {
		scanner = sc;

		try {
			bookController = new BookController();
			readerController = new ReaderController();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("SQL internal error: " + e.getMessage()
					+ ", Return to main menu.");
			return;
		}

		System.out.print("Enter reader Name: ");
		do {
			String readerName = scanner.nextLine();
			if (readerName.isEmpty()) {
				System.out.println("No reader enter, return main menu.");
				return;
			}
			currentReader = readerController.getReader(readerName);
			if (currentReader == null)
				System.out
						.println("Reader "
								+ readerName
								+ " not found, please try again or press enter to return main menu");
		} while (currentReader == null);

		try {
			bookingController = new BorrowController(currentReader);
		} catch (Exception ex) {
			ex.printStackTrace();
			System.out.println("Unknown internal error: " + ex.getMessage()
					+ ", Return to main menu.");
			return;
		}

		showUserInfo();
		if (checkHasLateReturn())
			return;
		showMenu();
	}

	private void showMenu() {
		int option;
		String[] options = { "Show borrow record", "Borrow book(s)",
				"Search book", "Renew", "Return Book", "To Main Menu" };
		do {
			option = ConsoleUtilities.showMenu(scanner, "Borrow Menu", options);

			switch (option) {
			case 1:
				showBookedRecord();
				System.out.print("\n Press any key to continue...");
				scanner.nextLine();
				break;
			case 2:
				borrowBook();
				break;
			case 3:
				searchBook();
				System.out.print("\n Press any key to continue...");
				scanner.nextLine();
				break;
			case 4:
				renewRecord();
				break;
			case 5:
				BorrowMenu.returnBook(scanner);
				break;
			}
		} while (option != 6);
	}

	private void showUserInfo() {
		String message = "User name: " + currentReader.getFullName()
				+ "\nUser id: " + currentReader.getId() + "\nUser Tel:"
				+ currentReader.getTel();

		ConsoleUtilities.printBox("Borrow Menu", message, 45);

	}

	private boolean checkHasLateReturn() {
		List<BookingRecord> expireRecordList = bookingController
				.getExpiryRecord();
		if (expireRecordList.size() > 0) {
			List<List<String>> items = new ArrayList<List<String>>();
			String[] header = { "ID", "Book name", "Return Date", "Fine" };
			int[] width = { 5, 30, 15, 5 };

			for (int i = 0; i < expireRecordList.size(); i++) {
				BookingRecord record = expireRecordList.get(i);
				String[] array = { String.valueOf(record.getBookID()),
						record.getBookName(), record.getReturnDateInString(),
						String.valueOf(bookingController.calculateFine(record)) };
				items.add(Arrays.asList(array));
			}

			ConsoleUtilities.printTable("Late Return Record", header, items,
					width);
			System.out
					.println("*** This reader has been blocked because reader have overdue borrow record ***");
			System.out
					.println("*** Please return these book and pay the fine first, press enter to return main menu ***");
			scanner.nextLine();
			return true;
		} else
			return false;
	}

	private List<BookingRecord> showBookedRecord() {
		List<BookingRecord> recordList = bookingController.getBookingRecord();
		List<List<String>> items = new ArrayList<List<String>>();
		String[] header = { "#", "ID", "Book name", "Return Date",
				"Renew Count" };
		int[] width = { 5, 5, 30, 15, 15 };

		if (recordList != null && recordList.size() > 0) {
			for (int i = 0; i < recordList.size(); i++) {
				BookingRecord record = recordList.get(i);
				String[] array = { String.valueOf(i + 1),
						String.valueOf(record.getBookID()),
						record.getBookName(), record.getReturnDateInString(),
						String.valueOf(record.getRenewCount()) };
				items.add(Arrays.asList(array));
			}
		} else {
			String[] empty = { "", "***", "No record  ***", "", "" };
			items.add(Arrays.asList(empty));
		}

		ConsoleUtilities.printTable("Booking Record", header, items, width);
		return recordList;
	}

	private void borrowBook() {
		int book_id = -999;
		Book book;
		do {
			System.out.print("Enter the book id, -1 to exit: ");
			try {
				book_id = scanner.nextInt();
				book = bookController.getBookById(book_id);
			} catch (InputMismatchException imex) {
				System.out.println("Please enter a valid number.");
				continue;
			} finally {
				scanner.nextLine();
			}

			if (book_id == -1)
				return;

			if (bookingController.borrowBook(book_id))
				System.out.println("Book: " + book.getName()
						+ " has been successful hired. ");
			else {
				ErrorMessage error = bookingController.getError();
				if (error.getErrorCode() == ErrorCode.BOOK_NOT_FOUND)
					System.out
							.println("Book ID: "
									+ book_id
									+ " can not be found, please check the book id is valid");
				else
					System.out.println("Book: " + error.getBook().getName()
							+ " can not be hired, " + error.getErrorMessage());
			}
		} while (book_id != -1);
	}

	private void renewRecord() {
		List<BookingRecord> renewItems = new ArrayList<BookingRecord>();
		showBookedRecord();
		List<BookingRecord> records = bookingController.getBookingRecord();
		if(records.size()>0){
		System.out
				.println("Enter the booking record index(#) to renew (eg: 1 2 3 , in single line), or enter \"all\" to renew all the record:");

		String input = scanner.nextLine();
		String[] inputArray = input.split(" ");
		if (input.equals("all")) {
			renewItems = records;
		} else {
			for (String s : inputArray) {
				try {
					int i = Integer.parseInt(s);
					if (i > 0 && i <= records.size())
						renewItems.add(records.get(i - 1));
				} catch (NumberFormatException e) {
					System.out.println(s + " is not a valid number, ignored");
				}
			}
		}

		List<List<String>> renewResult = new ArrayList<List<String>>();
		String[] header = {"Book ID", "Book Name","Success", "Return Date/Error"};
		int[] width = {8,30,9,18};
		for (BookingRecord r : renewItems) {
			boolean success = bookingController.renew(r);
			String msg;
			if (success){
				msg = r.getReturnDateInString();
			}
			else
				msg = bookingController.getError().getErrorMessage();
			
			String[] item = { String.valueOf(r.getBookID()),
					r.getBookName(),String.valueOf(success), msg,
					String.valueOf(r.getRenewCount())};
			renewResult.add(Arrays.asList(item));
		}
		if(renewItems.size() <= 0){
			String[] item = {"", "** No item to be renew **", "", ""};
			renewResult.add(Arrays.asList(item));
		}
		ConsoleUtilities.printTable("Renew Result", header, renewResult, width);
		} else {
			System.out.print("No record to be new,");
		}
		System.out.println("Press enter to continue..");
		scanner.nextLine();
	}

	private void searchBook() {
		System.out.print("Enter searching keyword: ");
		String keyword = scanner.nextLine();
		List<Book> result;
		try {
			result = bookController.search(keyword);
		} catch (SQLException e) {
			System.out.println("There are some error while search book");
			e.printStackTrace();
			return;
		}

		List<List<String>> items = new ArrayList<List<String>>();
		String[] header = { "Book ID", "Book name", "Status" };
		int[] width = { 12, 40, 15 };
		for (Book book : result) {
			String[] array = { String.valueOf(book.getId()), book.getName(),
					book.getStatus().toString() };
			items.add(Arrays.asList(array));
		}
		if (result.size() <= 0) {
			String[] empty = { "***", "No record  ***", "" };
			items.add(Arrays.asList(empty));
		}

		ConsoleUtilities.printTable("Search result", header, items, width);
	}

	public static void returnBook(Scanner sc) {
		System.out.println("Book return");
		System.out.println("-------------------------------------------");
		BorrowController borrow = null;
		BookController book = null;
		try {
			borrow = new BorrowController(null);
			book = new BookController();
		} catch (Exception e) {
			e.printStackTrace();
		}
		int input_id = -1;
		do {
			try {
				System.out
						.print("Enter book ID that want to return, enter -1 to exit: ");
				input_id = sc.nextInt();
				sc.nextLine();

				if (input_id == -1)
					return;
				Book bk = book.getBookById(input_id);
				if (bk == null) {
					System.out.println("Book id " + input_id + " not found.");
					continue;
				}

				if (borrow.returnBook(bk)) {
					System.out.printf("Book %s (id: %d) returned.\n",
							bk.getName(), bk.getId());
				} else {
					ErrorMessage error = borrow.getError();
					if (error.getErrorCode() == ErrorCode.BOOK_OVERDUE) {
						BookingRecord lateRecord = error.getErrorRecord();
						System.out
								.printf("*** Warning: Book %s (id: %d) is late for %d day. Total fine $%.2f\n",
										bk.getName(), bk.getId(),
										borrow.calculateExpireDay(lateRecord),
										borrow.calculateFine(lateRecord));
						System.out.print("Pay the fine? (Y/N): ");
						String input = sc.nextLine();
						if (input.equalsIgnoreCase("Y")) {
							borrow.returnBook(bk, true);
							System.out.printf("Book \"%s (id: %d)\" returned.\n",
									bk.getName(), bk.getId());
						}
					} else if(error.getErrorCode() == ErrorCode.BOOK_NOT_RESERVED){
						System.out.println("Book \"" + error.getBook().getName()
								+ "\" is not reserved");
					} else {		
						System.out.println("Book \"" + error.getBook().getName()
								+ "\" can not returned, "
								+ error.getErrorMessage());
					}
				}
			} catch (InputMismatchException in) {
				System.out
						.println("Your input is not a number, please enter a valid book id");
				sc.nextLine();
				continue;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out
						.println("Error when return books: " + e.getMessage());
				e.printStackTrace();
				continue;
			}
		} while (input_id != -1);
	}
}
